package com.cats.bi.aggservice.impl;

import com.cats.bi.aggservice.DataSourceAggService;
import com.cats.bi.aggservice.FilterAggService;
import com.cats.bi.aggservice.MetaAggService;
import com.cats.bi.enums.DataEnum;
import com.cats.bi.enums.FilterEnum;
import com.cats.bi.exception.GetException;
import com.cats.bi.exception.SaveException;
import com.cats.bi.pojo.dto.*;
import com.cats.bi.pojo.model.*;
import com.cats.bi.service.*;
import com.cats.bi.sqltool.basic.Select;
import com.cats.bi.sqltool.function.Distinct;
import com.cats.bi.utils.ListUtils;
import com.cats.bi.utils.ResponseVO;
import com.cats.echarts.utils.GsonUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author duxiaobo
 * @date 2021/8/125:49 下午
 */
@Service
@Slf4j
public class DataSourceAggServiceImpl implements DataSourceAggService {

    @Autowired
    private DataSourceService dataSourceService;

    @Autowired
    private NodeService nodeService;

    @Autowired
    private LinkService linkService;

    @Autowired
    private LinkDetailService linkDetailService;

    @Autowired
    private FilterAggService filterAggService;

    @Autowired
    private MetaAggService metaAggService;

    @Autowired
    private SqlAssemblyService sqlAssemblyService;

    @Autowired
    private CommService commService;

    @Override
    public DataSourceDto saveDataSource(DataSourceDto dataSourceDto) {
        DataSourceModel dataSourceModel = dataSourceService.parseDataSourceModel(dataSourceDto);
        boolean flag = dataSourceService.saveOrUpdate(dataSourceModel);
        if (!flag) {
            log.error("保存数据源异常,数据源={}", GsonUtil.format(dataSourceDto));
            throw new SaveException("保存数据源异常");
        }
        dataSourceDto.setId(dataSourceModel.getId());
        // 保存节点
        if (!CollectionUtils.isEmpty(dataSourceDto.getNodes())) {
            dataSourceDto.getNodes().forEach(nodeDto -> nodeDto.setDsId(dataSourceDto.getId()));
            saveNodes(dataSourceDto.getNodes());
        }
        // 保存数据源过滤条件
        if (!CollectionUtils.isEmpty(dataSourceDto.getFilters())) {
            dataSourceDto.getFilters().forEach(filterDataDto ->
                    filterDataDto.setAssociatedId(dataSourceDto.getId())
                            .setFilterEnum(FilterEnum.datasource)
            );
            filterAggService.saveFilterDataList(dataSourceDto.getFilters());
        }
        return dataSourceDto;
    }

    public List<LinkDto> saveLinks(List<LinkDto> links) {
        links.forEach(linkDto -> saveLink(linkDto));
        return links;
    }

    public LinkDto saveLink(LinkDto linkDto) {
        LinkModel linkModel = linkService.parseLinkModel(linkDto);
        boolean flag = linkService.saveOrUpdate(linkModel);
        if (!flag) {
            log.error("保存连接异常,{}", GsonUtil.format(linkDto));
            throw new SaveException("保存连接异常");
        }
        linkDto.setId(linkModel.getId());
        return linkDto;
    }

    public List<LinkDetailDto> saveLinkDetails(List<LinkDetailDto> linkDetails) {
        linkDetails.forEach(linkDetailDto -> saveLinkDetail(linkDetailDto));
        return linkDetails;
    }

    public LinkDetailDto saveLinkDetail(LinkDetailDto linkDetailDto) {
        LinkDetailModel linkDetailModel = linkDetailService.parseLinkDetailModel(linkDetailDto);
        boolean flag = linkDetailService.saveOrUpdate(linkDetailModel);
        if (!flag) {
            throw new SaveException("保存连接条件异常");
        }
        linkDetailDto.setId(linkDetailModel.getId());
        return linkDetailDto;
    }

    public List<NodeDto> saveNodes(List<NodeDto> nodes) {
        nodes.forEach(nodeDto -> saveNode(nodeDto));
        return nodes;
    }

    public NodeDto saveNode(NodeDto nodeDto) {
        NodeModel nodeModel = nodeService.parseNodeModel(nodeDto);
        boolean flag = nodeService.saveOrUpdate(nodeModel);
        if (!flag) {
            log.error("保存节点异常,节点数据={}", GsonUtil.format(nodeDto));
            throw new SaveException("保存节点异常");
        }
        nodeDto.setId(nodeModel.getId());
        if (!CollectionUtils.isEmpty(nodeDto.getLinks())) {
            nodeDto.getLinks().forEach(linkDto -> linkDto.setNodeId(nodeDto.getId()));
            saveLinks(nodeDto.getLinks());
        }
        return nodeDto;
    }

    @Override
    public DataSourceDto getDataSource(Long dsId) {
        if (Objects.isNull(dsId)) {
            return null;
        }
        DataSourceModel dataSourceModel = dataSourceService.getById(dsId);
        if (Objects.isNull(dataSourceModel)) {
            log.error("数据源不存在，数据源Id={}", dsId);
            throw new GetException("数据源不存在");
        }
        DataSourceDto dataSourceDto = dataSourceService.parseDataSourceDto(dataSourceModel);
        List<NodeDto> nodeDtoList = getNodesByDsId(dsId);
        dataSourceDto.setNodes(nodeDtoList);
        List<FilterDataDto> filterDataDtoList = filterAggService.getsByAssociatedIdAndFilterType(dsId, FilterEnum.datasource.getCode());
        dataSourceDto.setFilters(filterDataDtoList);
        return dataSourceDto;
    }

    private List<LinkDto> getLinksByNodeId(Long nodeId) {
        List<LinkModel> linkModels = linkService.getLinksByNodeId(nodeId);
        List<LinkDto> linkDtoList = linkModels.stream().map(linkModel -> linkService.parseLinkDto(linkModel)).collect(Collectors.toList());
        return linkDtoList;
    }

    public List<LinkDetailDto> getLinkDetailsByLinkId(Long linkId) {
        List<LinkDetailModel> linkDetailModels = linkDetailService.getLinkDetailsByLinkId(linkId);
        List<LinkDetailDto> linkDetailDtoList = linkDetailModels.stream().map(linkDetailModel -> linkDetailService.parseLinkDetailDto(linkDetailModel)).collect(Collectors.toList());
        return linkDetailDtoList;
    }

    public List<NodeDto> getNodesByDsId(Long dsId) {
        List<NodeModel> nodeModels = nodeService.getNodesByDsId(dsId);
        List<NodeDto> nodeDtoList = nodeModels.stream().map(nodeModel -> nodeService.parseNodeDto(nodeModel)).collect(Collectors.toList());
        nodeDtoList.forEach(nodeDto -> {
            List<LinkDto> linkDtoList = getLinksByNodeId(nodeDto.getId());
            nodeDto.setLinks(linkDtoList);
        });
        return nodeDtoList;
    }

    @Override
    public List<MetadataItemDto> getItemKeyByDsId(Long dsId, String dataType) {
        List<MetadataEntityDto> entityDtoList = getMetadataEntityByDsId(dsId);
        List<MetadataItemDto> metadataItemDtoList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(entityDtoList)) {

            entityDtoList.forEach(entityDto -> {
                if (!CollectionUtils.isEmpty(entityDto.getItems())) {
                    if (StringUtils.isBlank(dataType)) {
                        metadataItemDtoList.addAll(entityDto.getItems());
                    } else {
                        List<MetadataItemDto> itemDtoList = entityDto.getItems().stream().filter(metadataItemDto -> metadataItemDto.getDataEnum().equals(DataEnum.valueOf(dataType))).collect(Collectors.toList());
                        metadataItemDtoList.addAll(itemDtoList);
                    }


                }
            });
        }
        return metadataItemDtoList;
    }

    @Override
    public List<MetadataEntityDto> getMetadataEntityByDsId(Long dsId) {
        Set<String> entitySet = new HashSet<>();
        DataSourceDto dataSource = getDataSource(dsId);
        if (!CollectionUtils.isEmpty(dataSource.getNodes())) {
            dataSource.getNodes().forEach(nodeDto -> {
                entitySet.add(nodeDto.getEntityKey());
                if (!CollectionUtils.isEmpty(nodeDto.getLinks())) {
                    nodeDto.getLinks().forEach(linkDto -> {
                        entitySet.add(linkDto.getFromEntityKey());
                        entitySet.add(linkDto.getToEntityKey());
                    });
                }
            });
        }
        List<MetadataEntityDto> entityDtoList = entitySet.stream().map(entity -> metaAggService.getEntityByEntityKey(entity)).collect(Collectors.toList());

        return entityDtoList;
    }

    @Override
    public Object[] getDistinctDataInDataSource(DataSourceDto dataSourceDto, String entityKey, String itemKey) {
        Select dataSelect = sqlAssemblyService.assembleDataSource(dataSourceDto);
        Select select = new Select();
        select.add(new Distinct(dataSelect,"temp",entityKey+"_"+itemKey));
        List<Map<String, Object>> list = commService.getList(select.toString());
        Object[] data = ListUtils.getData(list, entityKey + "_" + itemKey, "");
        return data;
    }
}
